/**
 *
 *
 *
 *对网络的一个封装，model层
 *
 *此处实现的算法只能探测终端节点的丢失情况，需要通过间接的方法才能探测路由节点的丢失情况
 *
 *
 *
 */

#ifndef NODETOPOLOGY_H
#define NODETOPOLOGY_H

#include <QObject>
#include <QMap>
#include <QTimer>
#include "model/message.h"
#include "tools/constant.h"
#include "database/database.h"
#include "model/node.h"

//typedef QMap<QString,Node> QNodeNameMap;
typedef QMap<ushort,Node> QNodeMap;
typedef QList<ushort> QNodeList;

class NodeTopology : public QObject
{
    Q_OBJECT
public:
    explicit NodeTopology(QObject *parent = 0,unsigned int TestDuration = 1000*5,
                          unsigned int boundaryValue = 3,unsigned int spaceTime = 1000*8);



signals:
    /**
     * @brief sig_TestNode 在测试网络中节点是否丢失时，通过写入zigbee网络串口一些数据
     * @param ba 根据一定的约定条件已经字节化的数据
     */
    void sig_TestNode(const QByteArray& ba);//需要测试的节点信息,发送到串口发送
    /*
     *param: value 使用一种特殊的格式描述网络结构 例如XML格式，通过解析这段数据来建立网络视图
     *Note: 与维护网络结构的NodeTopology类型的对象相链接,需要判断一下在什么时候发出这个信号
     */
    void sig_netTopology(const QString &value);
    /**
     * @brief sig_nodeChange 发送给view层的数据，用来维护视图
     * @param adress 节点的定位，通过16位地址
     * @param status 节点的状态，false 丢失 true 还在
     * @note  如果不存在这个地址，则是新加入网络的节点,没有实现
     */

    void sig_nodeChange(const QString &adress,bool status);
    /**
     * @brief sig_nodeChange 只有终端节点使用
     * @param name 设备名
     * @param status
     */
    void sig_nodeChange(ushort name, bool status);

    /**
     * @brief sig_nodeChange 只有终端节点使用
     * @param n
     * @param status
     */
    void sig_nodeChange(const Node &n);

    void sig_nodeChange(int type,const QString &addr, const QString &paddr,
                        ushort _name,bool status);

    //void sig_nodeChange(Node *n);

    /**
     * @brief sig_Message  发送一个信息
     * @param me 信息对象
     */
    void sig_Message(const Message &me);
    /**
     * @brief sig_newNode 新节点发送到viewer层
     *
     * @param n 节点
     */
    void sig_newNode(const Node &n);
    /**
     * @brief sig_oldNode 在网络中然后丢失，然后重新加入网络的节点
     * @param n
     * @node 不会使用到
     */
    void sig_oldNode(const Node &n);


    /**
     * @brief sig_realTimeInfo 上报实时的信息到界面
     * @param info
     */
    void sig_realTimeInfo(const QString& info);

    /**
     * @brief sig_control_cmd 发送控制命令，这个
     * @param barr
     */
    void sig_control_cmd(const QByteArray &barr);

public slots:

#ifdef TEST_NET
    void test();
#endif


    /**
     * @brief slt_get_cmd 一切发送到给节点的命令，都需用发送到这边 节点的唯一标示是它的设备名，一切对设备的操作都根据设备名来
     * @param dev_name 设备名
     * @param _cmd 命令
     */
    void slt_get_cmd(ushort dev_name, quint8 _cmd);


    /**
     * @brief slt_stopTest 当zigbee端口关闭时，做清理工作
     */
    void slt_stopTest();
    /**
     * @brief slt_addAnode 向model层中添加一个节点，
     * @param n 节点对象，包含一些必要的信息
     * @note model层发生了改变，view层也需要及时更新
     */

    void slt_addAnode(const Node &n);
    /**
     * @brief slt_modifyTestDuration 修改测试的周期时长
     * @param t 秒数
     */
    void slt_modifyTestDuration(unsigned int t);
    /**
     * @brief slt_NodeInfo 由sig_TestNode发出的测试由此返回
     * @param address 节点地址
     */
    void slt_NodeInfo(const QString& address);//判断测试结果，有回复则节点未丢失

    /**
     * @brief slt_NodeTest 接受测试的反馈的信息
     * @param addr 节点地址
     * @param name 设备名
     */
    void slt_NodeTest(const QString &addr,ushort name);
    /**
     * @brief slt_buildNet 建立网络的槽，命令格式：节点地址：父节点地址
     * @param value 信息
     */
    void slt_buildNet(const QString &value);
    /**
     * @brief slt_buildNet 接受zigbee数据解析层上传的网络建立信号
     * @param addr 节点地址
     * @param parentAddr 父节点地址
     * @param name 设备名
     */
    void slt_buildNet(char type,const QString &addr,const QString &parentAddr,ushort name);


    /**
     * @brief slt_badData 处理bad值，添加相关的信息，组合成SMS信息发送到gsm模块
     * @param name 设备名，作为标识查到相关的节点
     * @param flag 数据分类标识
     * @param value 坏值
     */
    void slt_badData(ushort name,int flag,int value);


    /**
     * @brief slt_nodeClear0 有传感数据到来说明，节点未丢失，相应的节点权值清零
     * @param name 设备名
     */
    void slt_nodeClear0(ushort name);
private slots:
    /**
     * @brief slt_cyclicTestNet 进行网络的循环测试
     */
    void slt_cyclicTestNet();
    /**
     * @brief slt_testNet 节点丢失测试
     */
    void slt_testNet();


    void slt_testRouter(const Node &n);
private:
    QNodeMap map_nodes;
    unsigned int m_TestDuration;//轮转的测试时长
    QTimer m_testTime;//轮询的时间定时器
    QTimer m_controlTimer;//测试一个检点的时间定时器
    unsigned int m_boundaryValue;//边界值
    unsigned int m_spaceTime;//每次测试的间隔时长
    Node m_currentTestNode;//指向当前正在进行测试的节点
    int m_Testcounter;//测试次数计加器


    void allNodeAddSelfByOne();
    /**
     * @brief c_list 协调器的list，因为协调器只有一个，所以一个链表就行
     */
    QNodeList c_list;
    /**
     * @brief r_map 路由器map 路由器可能有好多，路由有好几个节点，一个路由可能是
     * 另一个路由的子节点还是其他的节点的父节点
     */
    QMap<ushort,QNodeList> r_map;//

    /**
     * @brief aRouterIsLost 测试一个
     * @param RouterNode
     * @return
     */
    bool aRouterIsLost(const Node & RouterNode) const;
    bool aCoordinatorIsLost() const;
    Node& getParent(const QString& parentAdd);

    void removeADEformRouter(ushort pname,ushort name);

    void removeFormCood(ushort name);

    void insertIntoRouter(ushort pname,ushort name);
    void insertIntoCood(ushort name);

    Node& getNodeByName(ushort name);

    void testRouterOrCood(const Node &n);

    Node& getCood();

    void clearARouter(ushort name);

    void doBadValue(int flag,int value,const QString& des);


    void restartTest();








};

#endif // NODETOPOLOGY_H
